Lerna 学习笔记

Lerna: https://www.lernajs.cn
yarn workspace: https://yarn.bootcss.com/docs/workspaces/

2021.5.30 星期日

背景

https://github.com/lerna/lerna

背景

MonoLith:一个项目,一个 Git 仓库。
multrepo:将项目分化为多个模块,并针对每一个模块单独的开辟一个 reporsitory来进行管理。
monorepo:是将所有的模块统一的放在一个主干分支之中管理。

lerna: Babel开发用来管理多包的工具,基于 Monorepo 理念在工具端的实现。
yarn: Facebook 贡献的 Javascript 包管理器。

lerna

A tool for managing JavaScript projects with multiple packages.

Lerna is a tool that optimizes the workflow around managing multi-package repositories with git and npm.

Lerna 是一个用来优化托管在git\npm上的多package代码库的工作流的一个管理工具,可以让你在主项目下管理多个子项目,从而解决了多个包互相依赖,且发布时需要手动维护多个包的问题。

两种工作模式

Fixed/Locked mode (default)

固定模式,通过lerna.json的版本进行版本管理。

vue,babel都是用这种,在publish的时候,会在lerna.json文件里面”version”: “0.1.5”,依据这个号,进行增加,只选择一次,其他有改动的包自动更新版本号。

Independent mode

lerna init –independent初始化项目。
lerna.json文件里面”version”: “independent”,
独立模式允许管理者对每个库单独改变版本号,每次发布的时候,需要为每个改动的库指定版本号

publish时得到一个提示符,提示每个已更改的包,以指定是补丁、次要更改、主要更改还是自定义更改。

实践

lerna工作流:
lerna boostrap(依赖包安装) –> 开发模块 –> git commit –> lerna changed(查看包变化) –> lerna publish。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
lerna init --independent
lerna boostrap --hoist

cd packages && mkdir commPkg pkg1 pkg2
# 创建新项目,或者现有项目

lerna add commPkg --scope=pkg1
lerna add commPkg --scope=pkg2

lerna run --parallel serve
## npm run dev:all
## npm run dev:system

# 提交 发布
git add .
git commit -m 'feat: sth.'

lerna changed
lerna publish

lerna.json 配置项

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
{
"version": "1.1.3", // independent
"npmClient": "npm", // cnpm;yarn: run all commands with yarn
"command": {
"publish": {
"ignoreChanges": ["ignored-file", "*.md"],
"message": "chore(release): publish",
"registry": "https://npm.xesv5.com"
},
"bootstrap": {
"scope": [], //
"ignore": "component-*",
"npmClientArgs": ["--no-package-lock"]
},
"version": {
"allowBranch": "master",
"conventionalCommits": true,
"createRelease": "github",
"exact": true,
"message": "chore(release): %s"
}
},
"packages": ["packages/*"] // ["projects/*", "src/**"]
}

version, 当前库的版本
npmClient, 允许指定命令使用的client, 默认是 npm, 可以设置成 yarn 或者cnpm
command.publish.ignoreChanges, 可以指定那些目录或者文件的变更不会被publish
command.bootstrap.ignore, 指定不受 bootstrap 命令影响的包
command.bootstrap.npmClientArgs, 指定默认传给 lerna bootstrap 命令的参数
command.bootstrap.scope, 指定那些包会受 lerna bootstrap 命令影响
packages, 指定包所在的目录

目录结构

The only restriction is that you can’t directly nest package locations, but this is a restriction shared by “normal” npm packages as well.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// Locating leaf packages under packages/* is considered a "best-practice"
├── lerna.json
├── package.json
|── packages/
├── foo-pkg
│ └── package.json
├── bar-pkg
│ └── package.json
├── baz-pkg
│ └── package.json
└── qux-pkg
└── package.json

// but is not a requirement for using Lerna.
├── lerna.json
├── package.json
├── src/
├── admin
│ ├── my-app
│ │ └── package.json
│ ├── stuff
│ │ └── package.json
│ └── things
│ └── package.json
├── profile
│ └── more-things
│ └── package.json
├── property
│ ├── more-stuff
│ │ └── package.json
│ └── other-things
│ └── package.json
└── upload
└── other-stuff
└── package.json

yarn的workspaces模式

lerna bootstrop --hoist 会将 packages 目录下的公共模块包抽离到最顶层。
不同版本号只会保留使用最多的版本;不同于顶层的依赖保留在自己的node_modules目录下。
<!– 但是这种方式会有一个问题,不同版本号只会保留使用最多的版本,这种配置不太好,当项目中有些功能需要依赖老版本时,就会出现问题。

有没有更优雅的方式?再介绍一个命令 yarn workspaces ,可以解决前面说的当不同的项目依赖不同的版本号问题, yarn workspaces会检查每个子项目里面依赖及其版本,如果版本不一致都会保留到自己的 node_modules 中,只有依赖版本号一致的时候才会提升到顶层。注意:这种需要在 lerna.json 中增加配置。

增加了这个配置后 不再需要 lerna bootstrap 来安装依赖了,可以直接使用 yarn install 进行依赖的安装。

注意:yarn install 无论在顶层运行还是在任意一个子项目运行效果都是可以。
–>
TODO: yarn workspaces 的必要性。
目前最常见的 monorepo 解决方案是 Lerna 和 yarn 的 workspaces 特性,基于lerna和yarn workspace的monorepo工作流。
由于yarn和lerna在功能上有较多的重叠,采用yarn官方推荐的做法,用yarn来处理依赖问题,用lerna来处理发布问题。

修改顶层 package.json 和 lerna.json

1
2
3
4
5
6
7
8
9
// # package.json 文件加入
"private": true,
"workspaces": [
"packages/*"
],

// # lerna.json 文件加入
"useWorkspaces": true,
"npmClient": "yarn",

原理

lerna 软链实现

软链是什么?

未使用 lerna 之前,想要调试一个本地的 npm 模块包,需要使用 npm link 来进行调试。


npm link可以在系统目录下建立包软链。软链可以不需要发布,就可以使用本地包,很好的提高开发效率。
lerna 也是软链的方式直接进行模块的引入和调试。

symlinkSync

lerna 同 nodejs中一样,通过 fs.symlinkSync(target,path,type)实现软链。

1
2
3
4
fs.symlinkSync(target,path,type)
target <string> | <Buffer> | <URL> // 目标文件
path <string> | <Buffer> | <URL> // 创建软链对应的地址
type <string>

源码:utils/create-symlink

1
2
3
4
5
6
7
8
9
10
11
function createSymbolicLink(src, dest, type) {
log.silly("createSymbolicLink", [src, dest, type]);

return fs
.lstat(dest)
.then(() => fs.unlink(dest))
.catch(() => {
/* nothing exists at destination */
})
.then(() => fs.symlink(src, dest, type));
}

lerna 应用

lerna 比较适合的场景:基础框架,组件库,工具类。
lerna库自己也是通过这种方式管理的。
<!– 1) 从零搭建一个 平台基础组件库项目
ui-component 中会存在 h5 组件库,web 组件库,mobile 组件库,以及对应的 doc 项目,三个项目通用的 common 代码。为了方便多个项目的联调,以及分别打包,这里采用了lerna 的管理方式。

2)框架类项目
公司组件库项目。
组件库项目类似上面实战的目录结构,但是会在 packages 包下添加很多其他的模块,比如 ui-h5 , example-h5 等

3)工具类项目
举例一些开源项目。
babel 使用的就是 lerna 进行管理
facebook/jest 使用的是 lerna 进行管理
alibaba/rax 使用的是 lerna 进行管理
–>
Lerna 用户列表:

babel/babel
webpack/webpack-cli
vuejs/vue-cli
facebook/create-react-app

结合项目

凡是涉及到两个项目及以上,有依赖关系,都可以用lerna/monorepo来管理。
但不是必须的。比如一个后端服务,和一个前端项目,可以用Multi-Repo管理。技术实现不一样,也无强依赖关系。
PS:可以考虑git submodule,subtree。

可以开放讨论,我们现在的哪些项目可以用到lerna。

繁星系统:multrepo vs monorepo 。

痛点解决

1) 资源浪费
通常情况下,一个项目只有一个主干,多 git repo 的方式,这样 node_module 会出现大量的冗余,比如它们都会安装 React、axios、lodash等包,浪费了大量存储空间。

2) 调试繁琐
很多公共的包通过 npm 安装,想要调试依赖的包时,需要通过 npm link 的方式进行调试。

3) 资源包升级/模块引用 问题
一个项目依赖了多个 npm 包,当某一个子 npm 包代码修改升级时,都要对主干项目包进行升级修改。

monorepo弊端

可能需要下载所有模块项目才可以运行。
可以看到所有的模块(既是优势也是劣势),包括开发者不需要关注的项目,一个项目会很大。
可以通过权限去控制。

更多

    • 抽离公共的配置:eslint,babel,webpack-config,oss等。
    • 抽离公共的模块:utils,axios,components等。
    • ci/cd 优化:既可以单独打包部署, 也可以一起打包部署在一台服务器。
    • Conventional commit 规范。条件验证,version_bump,生成 changelog,生成 git tag。

version 问题

工具

1
2
3
4
# cli 引导 lerna-wizard
npm i -g lerna-wizard
# 更新公共依赖 lerna-update-wizard
npm install --save-dev lerna-update-wizard

指令

init

目录结构.会创建3份文件(夹)
package.json
lerna.json
packages/

create

lerna create < name > [loc]
创建一个包,name包名,loc 位置可选

add

lerna add [@version] [–dev] [–exact] –scope=module-2

boostrap

  1. 为每个包安装依赖
  2. 链接相互依赖的库到具体的目录(symlink)
  3. 执行 npm run prepublish
  4. 执行 npm run prepare
    <!–
  5. 在每个 package 下面执行 npm install 。
  6. 根据各个 package 下 package.json 里面的 dependencies 和 devDependencies 配置,使用 symlink 在各个 package 的 node_modules 下面建立引用关系。
  7. 在每个 package 下执行 npm run prepublish 。
  8. 在每个 package 下执行 npm run prepare 。 –>

–hoist
将 packages 里重复的依赖提取到最外层的 node_modules 里,同时最外层的 package.json 也不会更新 dependency 信息,
所以不建议将公用依赖写到最外层的package.json里,而是重复写到每个子package.json 里,然后用 –hoist 提取出来

list

lerna list [–json]

import

导入本地已经存在的包

run

运行所有包里面的有这个script的命令。类比 exec
lerna run < script > – [..args]
lerna run --scope my-component test

exec

1
2
3
4
$ lerna exec -- < command > [..args] # runs the command in all packages
$ lerna exec -- rm -rf ./node_modules
$ lerna exec -- protractor conf.js
lerna exec --scope my-component -- ls -la

–concurrency
默认命令时并行执行的, 我们可以设置并发量为1
lerna exec –concurrency 1 – ls -la

–scope
lerna exec –scope my-component – ls -la

–stream
交叉并行输出结果
lerna exec –stream – babel src -d lib

–parallel

–no-bail
默认lerna exec,如果有命令返回了非0, 则会停止执行, 通过设置这个参数 忽略返回非0, 继续执行其它命令

项目包建立软链,类似npm link

clean

删除所有包的node_modules目录

lerna clean 不会删除项目最外层的根 node_modules

changed

列出下次发版lerna publish 要更新的包。

原理: 需要先git add,git commit 提交。 然后内部会运行git diff –name-only v版本号,搜集改动的包,就是下次要发布的。

lerna diff

显示自上次release tag以来有修改的包的差异, 执行 git diff

publish

发布最新改动的库

  1. 运行lerna updated来决定哪一个包需要被publish
  2. 如果有必要,将会更新lerna.json中的version
  3. 将所有更新过的的包中的package.json的version字段更新
  4. 将所有更新过的包中的依赖更新
  5. 为新版本创建一个git commit或tag
  6. 将包publish到npm上
1
2
3
# 某些发布的情况,开发者需要指定安装包版本,或者指定子目录发布。
lerna publish --dist-tag next #// 指定当前版本号
lerna publish --contents dist #// 指定dist目录为发布目录

–skip-git 将不会创建git commit或tag
–skip-npm将不会把包publish到npm上。

–canary
可以用来独立发布每个commit,不打tag

–npm-client
默认npm

–npm-tag
为发布的版本添加 dist-tag

–no-verify-access
不进行用户发布的权限校验

–registry
指定registry

–yes
用于ci自动输入 yes

version

识别出修改的包 –> 创建新的版本号 –> 修改package.json –> 提交修改,打上版本的tag –> 推送到git上。

–allow-branch
设置git上的哪些分支允许执行 lerna version 命令, 也可以在lerna.json中设置

–amend
把version的修改都合并到前一个commit, 而且不会推送哦。

–message
指定提交信息, 而不是自动生成的log
也可以在lerna.json配置

–conventional-commits
使用了这个选项, lerna会收集日志, 自动生成 CHANGELOG

–ignore-changes
忽略检查某些文件的修改
lerna version –ignore-changes ‘/*.md’ ‘/tests/**’
也可以在lerna.json中配置

–git-tag-version
添加git的tag, 默认true

–no-git-tag-version Do not commit or tag version changes.

使用​–no-push​会把tag推送一起禁止掉,好在禁止推送主分支只会报错,但不影响整个流程

yarn workspace

yarn workspace: https://yarn.bootcss.com/docs/workspaces/

It allows you to setup multiple packages in such a way that you only need to run yarn install once to install all of them in a single pass. 。

简而言之,workspace能帮助你更好的管理有多个子project的repo。你既可以在每个子project下使用独立的package.json管理你的依赖,又可以享受一条yarn命令安装或者升级所有依赖的都便利性。

npm 不支持 workspaces,所以之前安装依赖都要使用 yarn。
monorepo的项目结构,一般都会配合 yarn workspace 来管理包的依赖。

开始

1
2
3
4
5
6
{
"private": true,
"workspaces": [
"packages/*"
]
}

根目录执行 yarn install

1
2
3
4
5
6
7
rm -r project1/node_modules

yarn install

yarn workspace <workspace_name> <command>
yarn workspaces <command>
yarn workspaces info [--json]

使用 yarn workspaces 后无法直接 yarn add <pkg_name> 或 yarn remove <pkg_name>,需要指定工作区。

  • 安装根工作区(workspace root)的依赖
  • 给指定的工作区(包)安装单独的依赖
  • 给所有工作区安装依赖
  • 删除依赖
  • 执行指定工作区的 scripts 命令

与Lerna相比

Yarn的工作区是Lerna的工具可以(和做!)使用的底层原语。
他们绝不会尝试支持Lerna提供的高级功能,但通过实施Yarn内部的解决方案和链接步骤的核心逻辑,我们希望能够启用新的用法并提高性能。

提示与技巧

workspaces字段是包含每个工作区的路径的数组。由于追踪每个路径可能很乏味,因此该字段也接受glob模式!例如,Babel通过一个packages/*指令来引用它们的所有包。
工作空间足够稳定,可用于大规模应用程序,不应该改变常规安装的工作方式,但如果您认为他们正在破坏某些东西,可以通过将以下行添加到Yarnrc文件中来禁用它们:工作区 - 实验错误

制和注意事项

  • 程序包布局在您的工作空间和用户将得到的内容之间会有所不同(工作空间依赖关系将被升高到文件系统层次结构中)。对这种布局做出假设已经很危险,因为提升过程不规范,理论上这里没有什么新的东西。
  • 在上面的例子中,如果workspace-b依赖于workspace-apackage.json中引用的不同版本,依赖将从Github安装,而不是从本地文件系统链接。这是因为一些软件包实际上需要使用以前的版本才能构建新的版本(Babel就是其中之一)。
  • 根据文件夹层次结构,工作空间必须是工作空间根的子项。您不能也不能引用位于此文件系统层次结构之外的工作空间。
  • 目前不支持嵌套工作区。

lerna+yarn workspace

日志信息

)。
conventional-changelog -p angular -i CHANGELOG.md -s -r 2

注意:这里生成的是整个仓库的 changelog ,而非每个 package生成 changelog

lerna 版本升级

lerna version

lerna version的作用是进行version bump,支持手动和自动两种模式

只发布某个package

不支持,lerna官方不支持仅发布某个package,见 https://github.com/lerna/lerna/issues/1691,如果需要,只能自己手动的进入package进行发布,这样lerna自带的各种功能就需要手动完成且可能和lerna的功能相互冲突

由于lerna会自动的监测git提交记录里是否包含指定package的文件修改记录,来确定版本更新,这要求设置好合理的ignore规则(否则会造成频繁的,无意义的某个版本更新),好处是其可以自动的帮助package之间更新版本

例如如果ui-form依赖了ui-button,如果ui-button发生了版本变动,会自动的将ui-form的对ui-button版本依赖更新为ui-button的最新版本。 如果ui-form发生了版本变动,对ui-button并不会造成影响。

自动选择发布版本

使用–conventional-commits 参数会自动的根据conventional commit规范和git commit message记录帮忙确定更新的版本号。

手动选择发布版本

如果git commit message发现不太靠谱,且无法修改的话,那么需要手动的确认新版本,version默认是手动选择版本

version成功后会自动的推送到主分支,我一般是关闭主分支的推送权限的,这样就会导致推送失败,但是暂时没找到如何禁止推送主分支的好办法,使用​–no-push​会把tag推送一起禁止掉,好在禁止推送主分支只会报错,但不影响整个流程
lerna version自动生成的提交格式为“ publish xxx”,并不符合conventional-commit规范,因此需要加以修改,我们通过message参数可以修改自动生成的提交记录

Git多项目管理

基于Git有多种方式来解决这个问题:Git Submodule,Git Subtree,GitSlave和Google Repo。

Git Submodule

Git 1.5.3中加入了git submodule这个命令。
Git子模块允许你将一个Git仓库作为另一个Git仓库的子目录。它能让你将另一个仓库克隆到自己的项目中,同时还保持独立的提交。

默认情况下,子模块会将子项目放在一个与仓库同名的目录中。我们也可以通过在命令结尾添加一个path来指定放到其他地方。

不过还有更简单一点的方式。如果给git clone命令传递–recursive选项,它就会自动初始化并更新仓库中的每一个子模块。
如果你不想在子模块目录中手动抓取与合并,那么还有种更容易的方式。运行git submodule update –remote,Git将会进入子模块然后抓取并更新。

如果在此时提交,那么你会将父项目锁定为子模块master分支最新的代码。
提交子模块的改动最简单的选项是进入每一个子模块中然后手动推送到远程仓库。然而git push命令接受值为on-demand的–recurse-submodules参数,它会尝试为你这样做。
遍历子模块.Git提供了foreach子模块命令。$ git submodule foreach 'git checkout -b featureA'

子模块的问题

1) 在父项目中git pull并不会自动更新子模块,需要调用git submodule update来更新子模块信息。如果忘记调用git submodule update,那么你极有可能再次把旧的子模块依赖信息提交上去。
2) 调用git submodule update并不会将子模块切换到任何分支,默认情况下子模块处于“游离的 HEAD”的状态。如果此时我们改动子模块而没有检出一个工作分支,那调用git submodule update时你所做的任何改动都会丢失。
3) Git子模块在父项目中维护所有依赖的子模块版本,当包含大量子模块时,父项目的更新将很容发生冲突,并且父项目的维护历史与所有子模块的维护历史相互交织,维护成本也会比较高。

Git Subtree

Git在1.8.0版本引入了git subtree这个命令,
它使用Git的subtree merge策略来得到类似git submodule的结果。但本质上,它是将子项目的代码全部merge进父项目。
使用git subtree,你不仅可以将其他项目合并为父项目的一个子目录,而且可以从父项目提取某个子目录的全部历史作为一个单独的项目。

相比Git子模块

管理和更新流程比较方便
不再有.gitmodules文件
克隆仓库不再需要init和update等操作
删除时不再像git submodule那样费劲

GitSlave

GitSlave用于管理相关的一个父项目和多个Slave项目。
通常,它会将你要执行的Git常规操作顺序在父项目和Slave项目中执行一遍,所以当你执行pull操作,项目中的所有仓库会顺序执行pull操作。
GitSlave是对Git命令的封装,是被设计用于简化多仓库的Git操作,而不是要取代Git。

GitSlave的缺点

GitSlave被设计用于包含多个Slave仓库的中等大小项目的开发,其在父项目的.gitslave文件中记录所需子项目的信息,并在所有仓库中顺序执行相应Git操作的设计原理,注定其使用场景有一定局限性。

GitSlave并不会记录所需子项目的版本,所以其永远只是追踪子项目的最新版本,无法满足父项目基于某一特定版本子项目的场景,而此种场景在开发中却是极为常见。
GitSlave在父项目的.gitslave文件中记录相关子项目的信息,使得父项目本身的提交历史与子项目的增删历史相互交织在一起,一旦子项目增多,父项目的提交历史将变得混乱。

Google Repo

个优秀的基于Git的多项目管理系统设计需要满足如下2点:
记录子项目的远程地址、所需版本和对应的本地路径。
这个记录文件应该单独维护,而不应该污染任何一个仓库,因为它与这些仓库本身毫无关系。
Google Repo正是完美匹配这2个设计要点的Git多项目管理系统。

Repo是Google为了有效组织Android的源代码而开发的一个基于Git的管理工具。

subtree 和 submodule 切换历程

第一阶段:gulp等自动化工具手动同步
第二阶段:使用Git subtree

第三阶段:使用Git submodule
1.在新员工加入团队时:一次性clone项目,submodule可以一起clone出来,只需添加–recursive递归参数就可以了,而subtree并不行,只能手动添加,不过可以借助神器Yeoman(一个自动生成项目脚手架的工具)来实现。
2.subtree适合像配置文件这种需要跟着项目走的情况。
3.submodule适合在开发阶段时引用,到了生产环境会被打包到指定文件内,而本身并不用跟着版本走的情况。

git subtree

使用git subtree 有以下几个原因:

旧版本的git也支持(最老版本可以到 v1.5.2).
git subtree与git submodule不同,它不增加任何像.gitmodule这样的新的元数据文件.
git subtree对于项目中的其他成员透明,意味着可以不知道git subtree的存在.
当然,git subtree也有它的缺点,但是这些缺点还在可以接受的范围内:

必须学习新的指令(如:git subtree).
子仓库的更新与推送指令相对复杂。

1
2
3
4
5
6
7
8
9
git subtree add   --prefix=<prefix> <commit>
git subtree add --prefix=<prefix> <repository> <ref>
git subtree pull --prefix=<prefix> <repository> <ref>
git subtree push --prefix=<prefix> <repository> <ref>
git subtree merge --prefix=<prefix> <commit>
git subtree split --prefix=<prefix> [OPTIONS] [<commit>]

# 添加
git subtree add --prefix=sub/libpng https://github.com/test/libpng.git master --squash

(–squash参数表示不拉取历史信息,而只生成一条commit信息。)

注意,现在的photoshop仓库对于其他项目人员来说,可以不需要知道libpng是一个子仓库。什么意思呢?
当你git clone或者git pull的时候,你拉取到的是整个photoshop(包括libpng在内,libpng就相当于photoshop里的一个普通目录);当你修改了libpng里的内容后执行git push,你将会把修改push到photoshop上。
也就是说photoshop仓库下的libpng与其他文件无异。

1
2
3
4
5
6
7
8
9
10
11
12
# 从源仓库拉取更新
git subtree pull --prefix=sub/libpng https://github.com/test/libpng.git master --squash
# 推送修改到源仓库
git subtree push --prefix=sub/libpng https://github.com/test/libpng.git master
# 简化git subtree命令
# 我们已经知道了git subtree 的命令的基本用法,但是上述几个命令还是显得有点复杂,特别是子仓库的源仓库地址,特别不方便记忆。
# 这里我们把子仓库的地址作为一个remote,方便记忆:
git remote add -f libpng https://github.com/test/libpng.git
# 然后可以这样来使用git subtree命令:
git subtree add --prefix=sub/libpng libpng master --squash
git subtree pull --prefix=sub/libpng libpng master --squash
git subtree push --prefix=sub/libpng libpng master

Git-Repo

文档: https://gerrit.googlesource.com/git-repo/

基础

除了 git-repo 外的几个要么 子模块需要手动指定本地仓库路径、要么 主仓库与子仓库会产生污染 且操作不够简便化。所以最终就采用了 Google 的 Git-repo(Repo)

Repo 是对 Git 构成补充的多(可以巨多的那种)代码库管理工具,简单说就是使用 Python 在 Git 基础上开发的一系列脚本命令。

Manifest

Repo 管理的核心就在于 Manifest,每个采用 repo 管理的复杂多仓库项目都需要一个对应的 manifest 仓库,如 AOSP 的 manifest ,此仓库用来存储所有子仓库的配置信息,repo 也是读取此仓库的配置文件来进行管理操作。里面的配置就是 xml 定义的结构,一般有两个主要的配置:子仓库用到的仓库地址(remote)、子仓库详细配置信息(project)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?xml version="1.0" encoding="UTF-8"?>
<manifest>
<remote name="remote1"
alias="origin"
fetch=".."
review="https://android-review.googlesource.com/" />

<remote name="remote2"
alias="origin"
fetch="git@github.com:group2/"
review="https://android-review2.googlesource.com/" />

<default revision="master"
remote="remote1"
sync-j="4" />

<project path="build/make" name="platform/build" groups="pdk" >
<copyfile src="core/root.mk" dest="Makefile" />
<linkfile src="CleanSpec.mk" dest="build/CleanSpec.mk" />
</project>
<project path="build/blueprint" name="platform/build/blueprint" groups="pdk,tradefed" revision="other_branch" remote="remote1"/>

<!-- ... -->

</manifest>

remote: 远程仓库地址配置,可以多个。
project

子项目仓库配置,可以多个。
copyfile

project 的子节点属性.

Repo 命令

repo init -u yout_manifest_git_url 初始化了你的项目 repo 工作区后,repo sync,你就可以进入正常的特性开发状态了。

1
2
3
repo init -u your_project_git_url
repo sync
repo start

Jenkins

knowledge is no pay,reward is kindness
0%